/* eslint-disable no-param-reassign */
import React, { useLayoutEffect, useRef, useState } from "react";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import bgImg from "@assets/images/sky.png";
import earthBg from "@assets/images/earth_bg.png";
import starflake1 from "@assets/images/starflake1.png";
import starflake2 from "@assets/images/starflake2.png";
import human from "@assets/images/login_human.png";
import cloudImg from "@assets/images/cloud.png";
import moonImg from "@assets/images/moon.jpg";
import moonImg2 from "@assets/images/moon2.jpg";
import ground from "@assets/images/ground.png";
import _ from "lodash";
import styles from "./style.module.css";

const SCREEN_WIDTH = window.innerWidth;
const SCREEN_HEIGHT = window.innerHeight;
const depth = 1400;
let scene;
let camera;
let renderer;
let sphereGroup;
let earthMesh;
let moonMesh;
let particlesFirst = [];
let particlesSecond = [];
let parameters;
let cloudParameterFirst;
let cloudParameterSecond;
let renderCloudMoveFirst;
let renderCloudMoveSecond;
const materials = [];
const distance = SCREEN_WIDTH / 2 / Math.tan(Math.PI / 12);
const zAxisNumber = Math.floor(distance - depth / 2);
const particlesInitPosition = -zAxisNumber - depth / 2;
const zprogresssecond = particlesInitPosition * 0.1;

const ThreeSpace = function ThreeSpace() {
  const container = useRef(null);
  const box = useRef(null);

  useLayoutEffect(() => {
    container.current = document.createElement("div");
    container.current.style.height = `${SCREEN_HEIGHT}px`;
    box.current.appendChild(container.current);

    scene = new THREE.Scene();
    new THREE.TextureLoader().load(bgImg, (texture) => {
      const geometry = new THREE.BoxGeometry(SCREEN_WIDTH, SCREEN_HEIGHT, depth);
      const material = new THREE.MeshBasicMaterial({ map: texture, side: THREE.BackSide });
      const mesh = new THREE.Mesh(geometry, material);
      scene.add(mesh);
    });

    camera = new THREE.PerspectiveCamera(15, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 30000);
    const cameraTarget = new THREE.Vector3(0, 0, 0);
    camera.position.set(0, 0, zAxisNumber);
    camera.lookAt(cameraTarget);

    renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
    renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    container.current.appendChild(renderer.domElement);

    const controls = new OrbitControls(camera, renderer.domElement);
    // enabled设置为true是可以使用鼠标控制视角
    controls.enabled = false;
    controls.update();

    initLight();
    earthMesh = initSphereModal();
    moonMesh = initMoonModal();
    sphereGroup = initSphereGroup(earthMesh, moonMesh);
    particlesFirst = initSceneStar(particlesInitPosition);
    particlesSecond = initSceneStar(zprogresssecond);
    cloudParameterFirst = initSceneCloud(
      [
        new THREE.Vector3(-SCREEN_WIDTH / 10, 0, -depth / 2),
        new THREE.Vector3(-SCREEN_WIDTH / 4, SCREEN_HEIGHT / 8, 0),
        new THREE.Vector3(-SCREEN_WIDTH / 4, 0, zAxisNumber),
      ],
      200,
      100
    );
    cloudParameterSecond = initSceneCloud(
      [
        new THREE.Vector3(SCREEN_WIDTH / 8, SCREEN_HEIGHT / 8, -depth / 2),
        new THREE.Vector3(SCREEN_WIDTH / 8, SCREEN_HEIGHT / 8, zAxisNumber),
      ],
      200,
      100
    );
    renderCloudMoveFirst = renderCloudMove(cloudParameterFirst, 0.0002);
    renderCloudMoveSecond = renderCloudMove(cloudParameterSecond, 0.0008, 0.001);
    animate();
  }, []);

  const render = () => {
    if (earthMesh) {
      earthMesh.rotateY(0.01);
    }
    if (moonMesh) {
      moonMesh.rotateY(0.02);
    }
    if (sphereGroup) {
      sphereGroup.rotateY(0.005);
    }
    renderStarMove();
    renderCloudMoveFirst();
    renderCloudMoveSecond();
    renderer.render(scene, camera);
  };

  const animate = () => {
    requestAnimationFrame(animate);
    render();
  };

  // 初始化地球
  const initSphereModal = () => {
    const texture = new THREE.TextureLoader().load(earthBg);
    console.log(texture);
    const material = new THREE.MeshPhongMaterial({ map: texture });
    material.blendDstAlpha = 0;
    // 几何体
    const sphereGeometry = new THREE.SphereGeometry(100);
    sphereGeometry.phiStart = 23.5;
    // 模型
    const mesh = new THREE.Mesh(sphereGeometry, material);
    mesh.position.set(0, 0, 0);
    return mesh;
  };
  // 初始化月球
  const initMoonModal = () => {
    const texture = new THREE.TextureLoader().load(moonImg);
    const texture2 = new THREE.TextureLoader().load(moonImg2);
    const material = new THREE.MeshPhongMaterial({ map: texture, bumpMap: texture2 });
    material.blendDstAlpha = 0;
    const sphereGeometry = new THREE.SphereGeometry(25);
    const mesh = new THREE.Mesh(sphereGeometry, material);
    mesh.position.set(150, 0, 100);
    return mesh;
  };
  const initSphereGroup = (...modal: any[]) => {
    const group = new THREE.Group();
    group.position.set(-SCREEN_WIDTH / 2 + 400, SCREEN_HEIGHT / 2 - 300, -300);
    scene.add(group);
    modal.forEach((ele) => {
      group.add(ele);
    });
    return group;
  };
  // 光源
  const initLight = () => {
    const ambientLight = new THREE.AmbientLight(0xffffff, 1);
    // 右下角点光源
    const lightRightBottom = new THREE.PointLight(0x0655fd, 5, 0);
    lightRightBottom.position.set(0, 0, -200);
    scene.add(lightRightBottom);
    scene.add(ambientLight);
  };

  // 初始化场景星星效果
  const initSceneStar = (initZposition: number) => {
    const geometry = new THREE.BufferGeometry();
    const vertices: number[] = [];
    const pointsGeometry: any[] = [];
    const textureLoader = new THREE.TextureLoader();
    const sprite1 = textureLoader.load(starflake1);
    const sprite2 = textureLoader.load(starflake2);
    parameters = [
      [[0.6, 100, 0.75], sprite1, 50],
      [[0, 0, 1], sprite2, 20],
    ];
    // 初始化500个节点
    for (let i = 0; i < 500; i += 1) {
      /**
       * const x: number = Math.random() * 2 * width - width
       * 等价
       * THREE.MathUtils.randFloatSpread(width)
       */
      const x: number = THREE.MathUtils.randFloatSpread(SCREEN_WIDTH);
      const y: number = _.random(0, SCREEN_HEIGHT / 2);
      const z: number = _.random(-depth / 2, zAxisNumber);
      vertices.push(x, y, z);
    }
    geometry.setAttribute("position", new THREE.Float32BufferAttribute(vertices, 3));

    // 创建2种不同的材质的节点（500 * 2）
    for (let i = 0; i < parameters.length; i += 1) {
      const color = parameters[i][0];
      const sprite = parameters[i][1];
      const size = parameters[i][2];

      materials[i] = new THREE.PointsMaterial({
        size,
        map: sprite,
        blending: THREE.AdditiveBlending,
        depthTest: true,
        transparent: true,
      });
      materials[i].color.setHSL(color[0], color[1], color[2]);
      const particles = new THREE.Points(geometry, materials[i]);
      particles.rotation.x = Math.random() * 0.2 - 0.15;
      particles.rotation.z = Math.random() * 0.2 - 0.15;
      particles.rotation.y = Math.random() * 0.2 - 0.15;
      particles.position.setZ(initZposition);
      pointsGeometry.push(particles);
      scene.add(particles);
    }

    return pointsGeometry;
  };

  // 渲染星星的运动
  const renderStarMove = () => {
    particlesFirst.forEach((item) => {
      if (item.position.z + 1 > 0) {
        item.position.setZ(particlesInitPosition);
      } else {
        item.position.z += 1;
      }
    });

    particlesSecond.forEach((item) => {
      if (item.position.z + 1 > 0) {
        item.position.setZ(zprogresssecond);
      } else {
        item.position.z += 1;
      }
    });

    const time = Date.now() * 0.00005;
    for (let i = 0; i < materials.length; i += 1) {
      const color = parameters[i][0];

      const h = ((360 * (color[0] + time)) % 360) / 360;
      materials[i].color.setHSL(color[0], color[1], parseFloat(h.toFixed(2)));
    }
  };

  /**
   * 初始化云
   */
  const initSceneCloud = (route?: any, geometryWidth?: number, geometryHeigh?: number) => {
    const curve = new THREE.CatmullRomCurve3(route, false);
    const tubeGeometry = new THREE.TubeGeometry(curve, 100, 2, 50, false);
    const tubeMaterial = new THREE.MeshBasicMaterial({
      // color: "0x4488ff",
      opacity: 0,
      transparent: true,
    });
    const tube = new THREE.Mesh(tubeGeometry, tubeMaterial);
    scene.add(tube);

    const clondGeometry = new THREE.PlaneGeometry(geometryWidth, geometryHeigh);
    const cloudTexture = new THREE.TextureLoader().load(cloudImg);
    const clondMaterial = new THREE.MeshBasicMaterial({
      map: cloudTexture,
      blending: THREE.AdditiveBlending,
      depthTest: false,
      transparent: true,
    });
    const cloud = new THREE.Mesh(clondGeometry, clondMaterial);
    scene.add(cloud);
    return { tube, cloud, curve };
  };
  /**
   * 渲染云的动画
   */
  const renderCloudMove = (cloudParameter: any, speed: number, scaleSpeed = 0.0006, maxScale = 1, startScale = 0) => {
    let cloudProgress = 0;
    return () => {
      if (startScale < maxScale) {
        startScale += scaleSpeed;
        cloudParameter.cloud.scale.setScalar(startScale);
      }
      if (cloudProgress > 1) {
        cloudProgress = 0;
        startScale = 0;
      } else {
        cloudProgress += speed;
        if (cloudParameter.curve) {
          const point = cloudParameter.curve.getPoint(cloudProgress);
          if (point && point.x) {
            cloudParameter.cloud.position.set(point.x, point.y, point.z);
          }
        }
      }
    };
  };
  return (
    <div ref={box} className={styles.container}>
      <img className={styles.human} src={human} alt="" />
      <img className={styles.ground} src={ground} alt="" />
    </div>
  );
};
export default ThreeSpace;
